﻿using AdvancedTool.ExceptionHandler;
using AdvancedTool.Standard;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace AdvancedTool.CaChe
{
    namespace Feature
    {
        /// <summary>
        /// 消息中心
        /// </summary>
        public class MessageCenter
        {
            static ObjectCache<string, Delegate> FunctionBase = new ObjectCache<string, Delegate>((bool isnull, KeyDataManager dataManager) =>
            {
                if (isnull)
                {
                    throw new CacheException("无重建数据");
                }
                else
                {
                    return MethodActivictor.GetDelegate<Delegate>(null, dataManager["Method"].Value as MethodInfo);
                }
            });
            /// <summary>
            /// 注册委托
            /// </summary>
            /// <param name="message">启动委托的消息</param>
            /// <param name="Function">注册的委托</param>
            public static void Register(string message, Delegate Function)
            {
                FunctionBase.Add(message, Function, new KeyData(Function.Method, "Method"));
            }
            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="msg">发送的消息</param>
            /// <param name="paramers">对应的委托的函数</param>
            /// <returns>目标委托的函数返回值</returns>
            public static object Send(string msg, params object[] paramers)
            {
                if (FunctionBase.CacheExisit(msg))
                {
                    return FunctionBase[msg].DynamicInvoke(paramers);
                }
                else
                {
                    return null;
                }
            }
            /// <summary>
            /// 取消注册信息
            /// </summary>
            /// <param name="msg">需要取消的注册信息</param>
            public static void UnRegister(string msg)
            {
                FunctionBase.Remove(msg, true);
            }
        }
        /// <summary>
        /// 标准化的消息中心
        /// </summary>
        /// <typeparam name="Tdelegate">该消息中心所提供的委托类型</typeparam>
        public class StandardMessageCenter<Tdelegate> : MessageCenter where Tdelegate : Delegate
        {
            /// <summary>
            /// 注册信息
            /// </summary>
            /// <param name="msg">信息</param>
            /// <param name="function">信息相匹配的函数</param>
            public void RegisterMessage(string msg, Tdelegate function)
            {
                MessageCenter.Register(msg + GetHashCode(), function);
            }
            /// <summary>
            /// 发送消息
            /// </summary>
            /// <param name="msg">信息</param>
            /// <param name="paramers">对应函数的参数</param>
            /// <returns>对应函数的返回值</returns>
            public object SendMessage(string msg, params object[] paramers)
            {
                return MessageCenter.Send(msg + GetHashCode(), paramers);
            }
            /// <summary>
            /// 注销信息
            /// </summary>
            /// <param name="msg">需要注销的信息</param>
            public void UnRegisterMessage(string msg)
            {
                MessageCenter.UnRegister(msg + GetHashCode());
            }
        }
    }
    /// <summary>
    /// 关键数据
    /// </summary>
    public class KeyData
    {
        /// <summary>
        /// 成员名称，即数据备注
        /// </summary>
        public string MemberName
        {
            get;
            set;
        }
        /// <summary>
        /// 数据类型
        /// </summary>
        public Type DataType
        {
            get;
        }
        /// <summary>
        /// 数据实体
        /// </summary>
        public object Value
        {
            get;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="value">关键数据的值</param>
        /// <param name="DataName"></param>
        public KeyData(object value, string DataName)
        {
            Value = value;
            DataType = value.GetType();
            MemberName = DataName;

        }

    }
    /// <summary>
    /// 关键数据管理器。
    /// </summary>
    public class KeyDataManager
    {
        List<KeyData> Datas = new List<KeyData>();
        /// <summary>
        /// 根据成员名称（MemberName）得到关键数据
        /// </summary>
        /// <param name="name">成员名</param>
        /// <returns></returns>
        public KeyData this[string name]
        {
            get
            {
                foreach (KeyData tmp in Datas)
                {
                    if (tmp.MemberName.Equals(name))
                    {
                        return tmp;
                    }
                }
                throw new CacheException("无此关键数据");
            }
        }
        /// <summary>
        /// 当前关键数据个数
        /// </summary>
        public int DataCount => Datas.Count;
        /// <summary>
        /// 根据序号获取关键数据
        /// </summary>
        /// <param name="index">序号</param>
        /// <returns></returns>
        public KeyData this[int index]
        {
            get
            {
                if (index >= DataCount)
                {
                    throw new CacheException("超过数据最大序号，index应小于" + DataCount);
                }

                return Datas[index];
            }
        }
        /// <summary>
        /// 获取全部的关键数据
        /// </summary>
        /// <returns></returns>
        public KeyData[] GetDatas()
        {
            return Datas.ToArray();
        }
        bool IsLegal(KeyData[] datas)
        {
            List<string> nowhave = new List<string>();
            foreach (KeyData data in Datas)
            {
                nowhave.Add(data.MemberName);
            }
            foreach (KeyData keyData in datas)
            {
                if (nowhave.Contains(keyData.MemberName))
                {
                    return false;
                }
                else
                {
                    nowhave.Add(keyData.MemberName);
                }
            }
            return true;
        }

        public KeyDataManager()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="datas">需要添加管理的关键数据</param>
        public KeyDataManager(params KeyData[] datas)
        {
            AddRange(datas);
        }
        /// <summary>
        /// 添加关键数据
        /// </summary>
        /// <param name="data"></param>
        public void AddRange(params KeyData[] data)
        {
            if (IsLegal(data))
            {
                Datas.AddRange(data);
            }
            else
            {
                throw new CacheException("必须使所有关键数据的成员名称不同");
            }
        }
        /// <summary>
        /// 移除关键数据
        /// </summary>
        /// <param name="index">序号</param>
        public void Remove(int index)
        {
            Datas.RemoveAt(index);
        }
        /// <summary>
        /// 移除关键数据
        /// </summary>
        /// <param name="data">移除对象</param>
        public void Remove(params KeyData[] data)
        {
            foreach (KeyData d in data)
            {
                Datas.Remove(d);
            }
        }
        /// <summary>
        /// 清空关键数据
        /// </summary>
        public void Clear()
        {
            Datas.Clear();
        }
    }

    /// <summary>
    /// 数据缓存（根据缓存标记值以获取缓存的项目，缓存随时可能被GC回收，通过KeyData以储存缓存的关键数据，并通过关键数据恢复已被回收的缓存）
    /// </summary>
    /// <typeparam name="Tkey">缓存的标记值的数据类型</typeparam>
    /// <typeparam name="Tobject">缓存的项目类型</typeparam>
    public class ObjectCache<Tkey, Tobject> where Tobject : class
    {
        /// <summary>
        /// 缓存重生操作（当缓存被GC清除后，可根据预先提供的关键数据进行恢复操作）
        /// </summary>
        /// <param name="isnull">关键数据是否为空</param>
        /// <param name="dataManager">关键数据管理</param>
        /// <returns></returns>
        public delegate Tobject ReGenerateAction(bool isnull, KeyDataManager dataManager);
        /// <summary>
        /// 当调取已回收项时触发的事件
        /// </summary>
        public event ReGenerateAction OnReUseDeadItem;
        Dictionary<Tkey, KeyDataManager> KeyDataArray;
        Dictionary<Tkey, WeakReference> cache;
        DeadItems deadmamager;
        class DeadItems
        {
            internal int Count => items.Count;
            internal Tkey[] KeyArray => items.ToArray();
            internal bool IsExisit(Tkey key)
            {
                return items.Contains(key);
            }
            List<Tkey> items = new List<Tkey>();
            internal DeadItems(Dictionary<Tkey, WeakReference> cache)
            {
                Update(cache);
            }
            internal void Update(Dictionary<Tkey, WeakReference> cache)
            {
                items.Clear();

                foreach (Tkey key in cache.Keys)
                {
                    if (cache[key].IsAlive == false)
                    {
                        items.Add(key);
                    }
                }
            }

        }
        bool isstoredata;
        /// <summary>
        /// 是否需要关键数据，false将会清空当前所有的关键数据
        /// </summary>
        public bool KeyDataNeed
        {
            set
            {
                isstoredata = value;
                if (isstoredata == true && KeyDataArray == null)
                {
                    KeyDataArray = new Dictionary<Tkey, KeyDataManager>();
                }
                else if (isstoredata == false)
                {
                    KeyDataArray = null;
                }
            }
            get => isstoredata;
        }
        /// <summary>
        /// 当前的缓存数
        /// </summary>
        public int CacheCount => cache.Count;
        /// <summary>
        /// 已被回收的缓存数
        /// </summary>
        public int DeadItemCount
        {
            get
            {
                deadmamager.Update(cache);
                return deadmamager.Count;
            }
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存的标记数据</param>
        /// <returns></returns>
        public Tobject this[Tkey key]
        {
            get
            {
                if (cache.ContainsKey(key))
                {
                    if (cache[key].IsAlive)
                    {
                        return (Tobject)cache[key].Target;
                    }
                    else
                    {
                        if (OnReUseDeadItem != null)
                        {
                            if (KeyDataArray == null)
                            {
                                return OnReUseDeadItem(true, null);
                            }
                            else
                            {
                                if (KeyDataArray.ContainsKey(key))
                                {
                                    return OnReUseDeadItem(false, KeyDataArray[key]);
                                }
                                else
                                {
                                    return OnReUseDeadItem(true, null);
                                }
                            }

                        }
                        throw new CacheException("请添加OnReUseDeadItem，因为该缓存已被清理");
                    }
                }
                else
                {
                    throw new CacheException("无此标记数据");
                }
            }
            set
            {
                if (cache.ContainsKey(key))
                {
                    cache[key] = new WeakReference(value);
                }
                else
                {
                    Add(key, value);
                }
            }
        }
        /// <summary>
        /// 获取关键数据
        /// </summary>
        /// <param name="tkey">关键数据的标记数据</param>
        /// <returns></returns>
        public KeyDataManager GetKeyDatas(Tkey tkey)
        {
            if (KeyDataExisit(tkey))
            {
                return KeyDataArray[tkey];
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 设置关键数据
        /// </summary>
        /// <param name="key">关键数据的标记数据</param>
        /// <param name="isappend">是否追加，false则清空之前的关键数据</param>
        /// <param name="datas">需要设置的关键数据</param>
        public void SetKeyDatas(Tkey key, bool isappend, params KeyData[] datas)
        {
            if (KeyDataExisit(key))
            {
                if (!isappend)
                {
                    KeyDataArray[key] = new KeyDataManager(datas);
                }
                else
                {
                    KeyDataArray[key].AddRange(datas);
                }
            }
            else
            {
                if (cache.ContainsKey(key))
                {
                    KeyDataArray.Add(key, new KeyDataManager(datas));
                }
            }


        }
        /// <summary>
        /// 关键数据是否存在
        /// </summary>
        /// <param name="tkey"></param>
        /// <returns></returns>
        public bool KeyDataExisit(Tkey tkey)
        {
            if (KeyDataNeed)
            {
                return KeyDataArray.ContainsKey(tkey);
            }
            else
            {
                throw new CacheException("请将KeyDataNeed启动");
            }
        }
        /// <summary>
        /// 特定标记值的缓存是否存在
        /// </summary>
        /// <param name="key">缓存的标记值</param>
        /// <returns></returns>
        public bool IsAlive(Tkey key)
        {
            return cache[key].IsAlive;
        }
        /// <summary>
        /// 判断缓存是否存在
        /// </summary>
        /// <param name="tkey">缓存的标记值</param>
        /// <returns></returns>
        public bool CacheExisit(Tkey tkey)
        {
            return cache.ContainsKey(tkey);
        }
        /// <summary>
        /// 获取缓存数据
        /// </summary>
        /// <param name="key">缓存的标记值</param>
        /// <returns></returns>
        public Tobject GetObject(Tkey key)
        {
            return this[key];
        }
        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key">缓存的标记值</param>
        /// <param name="obj">缓存项目</param>
        /// <param name="keyDatas">缓存的关键数据</param>
        /// <returns></returns>
        public bool Add(Tkey key, Tobject obj, params KeyData[] keyDatas)
        {
            bool isdone = false;
            try
            {
                cache.Add(key, new WeakReference(obj));
                isdone = true;
            }
            catch
            {

            }

            if (isdone && keyDatas.Length > 0 && KeyDataNeed == true)
            {
                KeyDataArray.Add(key, new KeyDataManager(keyDatas));
            }
            return isdone;
        }
        /// <summary>
        /// 移除某项缓存
        /// </summary>
        /// <param name="tkey">缓存数据标记值</param>
        /// <param name="IsRemoveKeyData">是否同时移除相关的关键数据</param>
        /// <returns></returns>
        public bool Remove(Tkey tkey, bool IsRemoveKeyData)
        {
            if (IsRemoveKeyData)
            {
                if (KeyDataExisit(tkey))
                {
                    KeyDataArray.Remove(tkey);
                }
            }
            if (cache.ContainsKey(tkey))
            {
                cache.Remove(tkey);
                return true;
            }
            return false;


        }
        /// <summary>
        /// 清除所有被回收的缓存
        /// </summary>
        public void ClearDeadItem()
        {
            deadmamager.Update(cache);
            foreach (Tkey tkey in deadmamager.KeyArray)
            {
                cache.Remove(tkey);
                if (KeyDataNeed)
                {
                    if (KeyDataExisit(tkey))
                    {
                        KeyDataArray.Remove(tkey);

                    }
                }
            }
        }
        public ObjectCache()
        {
            Init(true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// 
        /// <param name="reGenerate">重造已回收缓存的事件方法</param>
        public ObjectCache(ReGenerateAction reGenerate)
        {
            Init(true);
            OnReUseDeadItem += reGenerate;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="needkeyData">是否需要关键数据备份</param>
        public ObjectCache(bool needkeyData)
        {
            Init(needkeyData);
        }
        void Init(bool needkeyData)
        {
            KeyDataNeed = needkeyData;
            cache = new Dictionary<Tkey, WeakReference>();
            deadmamager = new DeadItems(cache);
        }
    }
}
